#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include "globals.h"
#include "exiterror.h"


/*/////////////////////// Constantes de exiterror - BEGIN - /////////////////////////////*/
/*///////////////////////////////////////////////////////////////////////////////////////*/

#define ERROR_STR_SUCCESS                       "Process completed."
#define ERROR_STR_INVALID_OPTION                "Invalid option."
#define ERROR_STR_MISSING_REQUIRED_PARAMETER    "Missing required parameter."
#define ERROR_STR_INVALID_COMMAND_LINE          "Invalid command line."
#define ERROR_STR_ONLY_ONE_BUBBLE		"Option -m (--bubble) is duplicated."
#define ERROR_STR_ONLY_ONE_HEAP                	"Option -p (--heap) is duplicated."
#define ERROR_STR_ONLY_ONE_ALGORITHM		"Only one algorithm can be selected."
#define ERROR_STR_BAD_INPUT_FILES_COUNT		"Input file(s) missing."
#define ERROR_STR_ONLY_ONE_OUTPUT               "Option output is duplicated."
#define ERROR_STR_ALLOCATING_MEMORY             "Cannot allocate memory."
#define ERROR_STR_CANNOT_OPEN_INPUT_FILE        "Cannot open input file:\n\"%s\"."
#define ERROR_STR_CANNOT_OPEN_INPUT_FILE_AUX    "Cannot open input file."
#define ERROR_STR_CANNOT_OPEN_OUTPUT_FILE       "Cannot open ouput file:\n\"%s\"."
#define ERROR_STR_CANNOT_OPEN_OUTPUT_FILE_AUX   "Cannot open ouput file."
#define ERROR_STR_READING_FROM_INPUT_FILE       "Cannot read from input file:\n\"%s\n."
#define ERROR_STR_READING_FROM_INPUT_FILE_AUX   "Cannot read from input file."
#define ERROR_STR_WRITING_TO_OUTPUT             "Cannot write to output."

#define ERROR_STR_UNEXPECTED			"Unexpected error."

#define ERROR_STR_FATAL_DESC			"Fatal error (code %d): %s\n"
#define ERROR_STR_SUCCESS_DESC			"Success (code %d): %s\n"

/*///////////////////////// Constantes de exiterror - END - /////////////////////////////*/
/*///////////////////////////////////////////////////////////////////////////////////////*/


/*
Convierte un código de error pasado por parámetro en un mensaje de texto
descriptivo y lo imprime por stderr.

1er parámetro: Código de error.


devuelve: -
*/
void messageerror (const int status)
{
        char* pcmessage;
        char* pcauxmsg = NULL;

        /* Esun simple switch que busca la descripción para el erorr indicado. */
        switch (status)
        {
        case ERROR_SUCCESS:
                pcmessage = ERROR_STR_SUCCESS;
                break;
        case ERROR_INVALID_OPTION:
                pcmessage = ERROR_STR_INVALID_OPTION;
                break;
        case ERROR_MISSING_REQUIRED_PARAMETER:
                pcmessage = ERROR_STR_MISSING_REQUIRED_PARAMETER;
                break;
        case ERROR_INVALID_COMMAND_LINE:
                pcmessage = ERROR_STR_INVALID_COMMAND_LINE;
                break;
        case ERROR_ONLY_ONE_BUBBLE:
                pcmessage = ERROR_STR_ONLY_ONE_BUBBLE;
                break;
        case ERROR_ONLY_ONE_HEAP:
                pcmessage = ERROR_STR_ONLY_ONE_HEAP;
                break;
        case ERROR_ONLY_ONE_ALGORITHM:
                pcmessage = ERROR_STR_ONLY_ONE_ALGORITHM;
                break;
        case ERROR_ONLY_ONE_OUTPUT:
                pcmessage = ERROR_STR_ONLY_ONE_OUTPUT;
                break;
        case ERROR_BAD_INPUT_FILES_COUNT:
                pcmessage = ERROR_STR_BAD_INPUT_FILES_COUNT;
                break;
        case ERROR_ALLOCATING_MEMORY:
                pcmessage = ERROR_STR_ALLOCATING_MEMORY;
                break;

                /*
                En estos casos si llegase a fallar malloc, lo cual es factible ya que nos
                encontramos en una codición de error no se muestra el nombre del archivo de
                entrada que se estaba procesando.
                 */
        case ERROR_CANNOT_OPEN_INPUT_FILE:

                pcauxmsg = (char*) malloc (strlen (ERROR_STR_CANNOT_OPEN_INPUT_FILE) +
                                           strlen (pprocfilename) + 1);

                if (pcauxmsg)
                {
                        sprintf (pcauxmsg, ERROR_STR_CANNOT_OPEN_INPUT_FILE, pprocfilename);
                        pcmessage = pcauxmsg;
                }
                else
                        pcmessage = ERROR_STR_CANNOT_OPEN_INPUT_FILE_AUX;

                break;


        case ERROR_READING_FROM_INPUT_FILE:

                pcauxmsg = (char*) malloc (strlen (ERROR_STR_READING_FROM_INPUT_FILE) +
                                           strlen (pprocfilename) + 1);

                if (pcauxmsg)
                {
                        sprintf (pcauxmsg, ERROR_STR_READING_FROM_INPUT_FILE, pprocfilename);
                        pcmessage = pcauxmsg;
                }
                else
                        pcmessage = ERROR_STR_READING_FROM_INPUT_FILE_AUX;

                break;

        case ERROR_CANNOT_OPEN_OUTPUT_FILE:

                pcauxmsg = (char*) malloc(strlen(ERROR_STR_CANNOT_OPEN_OUTPUT_FILE) +
                                          strlen(poutputfilename) + 1);

                if (pcauxmsg)
                {
                        sprintf(pcauxmsg, ERROR_STR_CANNOT_OPEN_OUTPUT_FILE, poutputfilename);
                        pcmessage = pcauxmsg;
                }
                else
                        pcmessage = ERROR_STR_CANNOT_OPEN_OUTPUT_FILE_AUX;

                break;

        case ERROR_WRITING_TO_OUTPUT:
                pcmessage = ERROR_STR_WRITING_TO_OUTPUT;
                break;

        default:
                pcmessage = ERROR_STR_UNEXPECTED;
        }

        /* Imprimo el mensaje por stderr.. */
        fprintf(stderr, status ? ERROR_STR_FATAL_DESC : ERROR_STR_SUCCESS_DESC, status, pcmessage);

        /* Libero la memoria dinámica. */
        if (pcauxmsg)
                free (pcauxmsg);

}


/*
Imprime por stderr un mensaje.

1er parámetro: Mensaje con formato.
n-avo parámetro: Parámetros de formato.

devuelve: -
*/
void messageinfo(const char * format, ...)
{
        va_list ap;
        va_start(ap, format);
        vfprintf(stderr, format, ap);
        va_end(ap);
}
